package com.fulizhe.catlocal.integration.struts2;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;

import javax.sql.DataSource;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.logging.slf4j.Slf4jImpl;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.AutoMappingBehavior;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.LocalCacheScope;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import org.apache.ibatis.type.JdbcType;

/**
 * @author Siva
 * 
 */
public class MyBatisUtil {
	public static final String MYBATIS_CONFIG_FILE_CLASSPATH = "./mybatis-config.xml";

	private static SqlSessionFactory xmlSqlSessionFactory;

	// private static SqlSessionFactory javaSqlSessionFactory;

	public static SqlSessionFactory getSqlSessionFactoryUsingXML() {
		if (xmlSqlSessionFactory == null) {
			xmlSqlSessionFactory = getSqlSessionFactoryUsingSpecialXML(MYBATIS_CONFIG_FILE_CLASSPATH);
		}

		return xmlSqlSessionFactory;
	}

	public static SqlSessionFactory getSqlSessionFactoryUsingSpecialXML(String xmlConfigFilePath) {
		try {
			InputStream inputStream = Resources.getResourceAsStream(xmlConfigFilePath);
			return getSqlSessionFactory(inputStream);
		} catch (IOException e) {
			throw new RuntimeException(e);
		} catch (Exception e) {
			System.out.println(e);
			throw new RuntimeException(e);
		}
	}

	public static SqlSessionFactory getSqlSessionFactory(InputStream configInputStream) {
		try {
			SqlSessionFactory xmlSqlSessionFactory = new SqlSessionFactoryBuilder().build(configInputStream);

			return xmlSqlSessionFactory;
		} catch (Exception e) {
			System.out.println(e);
			throw new RuntimeException(e);
		}
	}

	/**/
	public static <MapperType> MapperType getMapper(Class<MapperType> mapperClz) {
		SqlSessionFactory sqlSessionFactoryUsingJavaAPI = getSqlSessionFactoryUsingJavaAPI(
				getSqlSessionFactoryUsingXML().getConfiguration().getEnvironment().getDataSource(), mapperClz);

		return sqlSessionFactoryUsingJavaAPI.getConfiguration().getMapper(mapperClz,
				sqlSessionFactoryUsingJavaAPI.openSession());
	}

	public static <MapperType> SqlSessionFactory getSqlSessionFactoryUsingJavaAPI(Class<MapperType> mapperClz) {
		return getSqlSessionFactoryUsingJavaAPI(
				getSqlSessionFactoryUsingXML().getConfiguration().getEnvironment().getDataSource(), mapperClz);
	}

	/**/
	public static <MapperType> SqlSessionFactory getSqlSessionFactoryUsingJavaAPI(final DataSource defaultDS,
			Class<MapperType> mapperClz) {

		try {
			DataSource dataSource = defaultDS;
			TransactionFactory transactionFactory = new JdbcTransactionFactory();
			Environment environment = new Environment("development", transactionFactory, dataSource);
			Configuration configuration = new Configuration(environment);
			// configuration.getTypeAliasRegistry().registerAlias("student",
			// Student.class);
			// configuration.getTypeHandlerRegistry().register(PhoneTypeHandler.class);
			configuration.addMapper(mapperClz);

			configuration.setCacheEnabled(true);
			configuration.setLazyLoadingEnabled(false);
			configuration.setMultipleResultSetsEnabled(true);
			configuration.setUseColumnLabel(true);
			configuration.setUseGeneratedKeys(false);
			configuration.setAutoMappingBehavior(AutoMappingBehavior.PARTIAL);
			configuration.setDefaultExecutorType(ExecutorType.SIMPLE);
			configuration.setDefaultStatementTimeout(25);
			configuration.setSafeRowBoundsEnabled(false);
			configuration.setMapUnderscoreToCamelCase(false);
			configuration.setLocalCacheScope(LocalCacheScope.SESSION);
			configuration.setAggressiveLazyLoading(true);
			configuration.setJdbcTypeForNull(JdbcType.OTHER);
			configuration.setLogImpl(Slf4jImpl.class);
			Set<String> lazyLoadTriggerMethods = new HashSet<String>();
			lazyLoadTriggerMethods.add("equals");
			lazyLoadTriggerMethods.add("clone");
			lazyLoadTriggerMethods.add("hashCode");
			lazyLoadTriggerMethods.add("toString");
			configuration.setLazyLoadTriggerMethods(lazyLoadTriggerMethods);
			getSqlSessionFactoryUsingXML().getConfiguration().getInterceptors().stream()
					.forEach(configuration::addInterceptor);

			return new SqlSessionFactoryBuilder().build(configuration);

		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

}
